<?php

namespace App\Console\Commands;

use App\Common\RedisCache\FetchVideoCache;
use App\Common\RedisCache\UserCache;
use App\Common\RedisCache\UserFetchVideo;
use chan;
use Co;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
use Swoole\Coroutine;
use function Co\run;

class FetchVideoCommand extends Command
{
    protected $signature   = 'FetchVideoFromInternet {type?}';
    protected $description = '从互联网上拉取视频';

    public function handle(): bool
    {
        if ($this->argument('type') == 'test') {
            $this->testOfGoroutine();
            return true;
        }
        //每天重置新域名
        if ($this->argument('type') == 'bb') {
            $html = file_get_contents('https://bb9238.com/video/video_list.html?video_type=1&page_index=1');
            $preg = '#var c = (.*)var d#isU';
            preg_match_all($preg, $html, $host);
            $file = fopen('sh/hots.txt','w');
            $host = explode('|', substr(trim($host[1][0]),0 ,strlen(trim($host[1][0]))-1))[2];
            fwrite($file, $host);
            fclose($file);
            Log::info('重置了hosts：'.$host);
            return true;
        }
        //每周清空数据
        if ($this->argument('type') == 1) {
            return $this->everyWeekClear();
        }
        return true;
    }

    public function everyWeekClear(): bool
    {
        $file = fopen('sh/number.txt','w');
        fwrite($file,'1');
        fclose($file);
        $userCache = new UserCache();
        $userCache->setKeyParameter(['fetchVideo']);
        $oldPage   = $userCache->get();
        $userCache->set(1);
        $userHash = new UserFetchVideo();
        $userHash->setKeyParameter();
        $userHash->setFieldParameter([date('md')]);
        $userHash->set($oldPage);
        $redis     = new FetchVideoCache();
        $redis->setKeyParameter();
        $redis->del();
        exec('mkdir -p storage/video'.date('md').' && cp storage/video/* storage/video'.date('md'));
        exec('rm -rf storage/video/*');
        Log::info('清空了上周数据...');
        return true;
    }

    /**
     * 协程处理并发demo
     * @return void
     */
    public function testOfGoroutine()
    {
        run(function () {//协程容器，相当main函数
            $channel = new chan(11);
            for ($i = 0; $i < 10; $i++) {
                go(function () use ($channel, $i) {//10个协程处理任务，完成后push到通道
                    $taskId = $this->handleTask();
                    $channel->push(['taskId' => $taskId, 'index' => $i, 'coroutineId' => Co::getCid()]);
                });
            }
            //一个协程一直从通道中pop数据
//            go(function () use ($channel) {
                while (true) {
                    $data = $channel->pop(2.0);
                    if (empty($data)) {
                        Co::sleep(10.0);
                        continue;
                    }
                    //处理业务逻辑
                    Log::info($data);
                }
//            });
        });
    }

    public function handleTask(): int
    {
        sleep(3);
        return rand(1000,9999);
    }

    /**
     * waitGroup 处理并发
     * @return array
     */
    public function testWaitGroup(): array
    {
        //返回结果，犹豫变量作用域问题，要使用引用传递赋值
        $result = [];
        $coroutineCounter = 10;
        //declare a coroutine scheduler
        run(function () use (&$result, $coroutineCounter) {
            $waitGroup = new Co\WaitGroup();
            $waitGroup->add($coroutineCounter);
            for ($i = 0; $i < $coroutineCounter; $i++) {
                go(function () use ($waitGroup, &$result, $i) {
                    $taskId = $this->handleTask();
                    $result[] = [
                        'taskId' => $taskId,
                        'workerIndex' => $i,
                        'workerId' => Co::getCid(),
                    ];
                    $waitGroup->done();
                });
            }
            $waitGroup->wait();
        });
        return $result;
    }

    public function testVariableScope(): bool
    {
        $variable= 2222;
        $function = function($variables) use ($variable) {
            dump($variable);
            dump($variables);
            //此处赋值是变量作用域只在闭包内部，不影响外部变量
            $variables = 1111;
        };
        $function(1111);
        dump($variable);
        return true;
    }
}
